package com.asiainfo.ai.gateway.util;

import com.asiainfo.ai.gateway.exception.authc.TokenExpiredException;
import com.asiainfo.ai.gateway.exception.authc.TokenType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.MacSigner;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @author zhaoxu
 */
@Slf4j
public class JwtTokenUtil {
    public static final String EXP = "exp";

    /**
     * create by: zhaoxu
     * description: 解析jwtToken为map类型
     *
     * @param jwtToken jwtToken
     * @return Map<String, Object>
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> parsingJwtToken(String jwtToken, String jwtSigningKey, ObjectMapper objectMapper) {
        MacSigner signingKey = new MacSigner(jwtSigningKey);
        Jwt jwt = JwtHelper.decodeAndVerify(jwtToken, signingKey);
        Map<String, Object> claimMap;
        try {
            claimMap = objectMapper.readValue(jwt.getClaims(), Map.class);
        } catch (IOException e) {
            throw new TokenExpiredException(TokenType.JWT_TOKEN, jwtToken,
                    new Exception("jwt token转换为map类型异常:" + e.getMessage()));
        }
        return claimMap;
    }

    /**
     * create by: zhaoxu
     * description: 验证jwtToken是否为有效token
     *
     * @param jwtToken jwtToken
     * @param claimMap claimMap
     */
    public static void verifyJwtTokenIsValid(String jwtToken, Map<String, Object> claimMap) {
        if (Objects.isNull(claimMap) || !claimMap.containsKey(EXP) || claimMap.get(EXP) == null
                || StringUtils.isBlank(String.valueOf(claimMap.get("exp")))) {
            throw new TokenExpiredException(TokenType.JWT_TOKEN, jwtToken,
                    new Exception("当前Token没有设置失效时间，为无效Token!"));
        }
    }

    /**
     * 验证token是否过期
     *
     * @param expSecondTime token过期时间（秒级）
     */
    public static boolean validateJwtExpire(Long expSecondTime) {
        Long currentTime = Instant.now().getEpochSecond();
        return checkTime(expSecondTime, currentTime);
    }

    public static boolean validateJwtExpire(Instant expSecondTime) {
        long now = Instant.now().getEpochSecond();
        return checkTime(expSecondTime.getEpochSecond(), now);
    }

    private static boolean checkTime(Long expSecondTime, Long currentTime) {
        if (currentTime > expSecondTime) {
            if (log.isTraceEnabled()) {
                log.trace("验证token过期，当前时间:{},token过期时间:{}", convertSecondToDateStr(currentTime), convertSecondToDateStr(expSecondTime));
            }
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    public static String convertSecondToDateStr(Long secondTime) {
        Calendar calendar = Calendar.getInstance();
        //转换为毫秒
        calendar.setTimeInMillis(secondTime * 1000);
        Date date = calendar.getTime();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return format.format(date);
    }

}
